package com.vr.cloudpicture.manager.websocket.handler;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.vr.cloudpicture.manager.websocket.disruptor.PictureEditEventProducer;
import com.vr.cloudpicture.manager.websocket.model.PictureEditRequestMessage;
import com.vr.cloudpicture.manager.websocket.model.PictureEditResponseMessage;
import com.vr.cloudpicture.manager.websocket.model.enums.PictureEditMessageTypeEnum;
import com.vr.cloudpicture.manager.websocket.strategy.PictureEditMessageStrategy;
import com.vr.cloudpicture.manager.websocket.strategy.PictureEditMessageStrategyFactory;
import com.vr.cloudpicture.model.dto.user.UserLogin;
import com.vr.cloudpicture.model.vo.UserVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

/**
 * 图片编辑的websocket处理器
 *
 * @author hzh
 * @date 2025/05/28
 */
@Slf4j
@Component
@AllArgsConstructor
public class PictureEditHandler extends TextWebSocketHandler {
    private final PictureEditMessageStrategyFactory pictureEditMessageStrategyFactory;
    private final PictureEditEventProducer pictureEditEventProducer;


    /**
     * websocket建立连接后
     *
     * @param session 会话
     * @throws Exception 例外
     */
    @Override
    public void afterConnectionEstablished(@NotNull WebSocketSession session) throws Exception {
        // 拿到保存会话里的信息，放到会话集合里
        UserLogin user = (UserLogin) session.getAttributes().get("user");
        Long pictureId = (Long) session.getAttributes().get("pictureId");
        PictureEditBroadcast.addSession(pictureId, session);
        // 构建响应
        PictureEditResponseMessage pictureEditResponseMessage = new PictureEditResponseMessage();
        pictureEditResponseMessage.setType(PictureEditMessageTypeEnum.INFO.getValue());
        String message = String.format("%s加入编辑", user.getUserName());
        pictureEditResponseMessage.setMessage(message);
        pictureEditResponseMessage.setUser(BeanUtil.toBean(user, UserVO.class));
        // 广播给同一张图片的用户
        PictureEditBroadcast.broadcastToPicture(pictureId, pictureEditResponseMessage);
    }
    /**
     * 接受客户端的消息
     */
    @Override
    protected void handleTextMessage(@NotNull WebSocketSession session, @NotNull TextMessage message) throws Exception {
        // 将消息转换成PictureEditRequestMessage对象
        PictureEditRequestMessage requestMessage = JSONUtil.toBean(message.getPayload(), PictureEditRequestMessage.class);
        String type = requestMessage.getType();

        // 从会话中拿到参数
        Long pictureId = (Long) session.getAttributes().get("pictureId");
        UserLogin user = (UserLogin) session.getAttributes().get("user");

        // // 根据消息类型用不同的策略处理
        // PictureEditMessageStrategy strategy = pictureEditMessageStrategyFactory.getStrategyByMessageType(type);
        // strategy.handle(requestMessage, session, user, pictureId);

        // 采用无锁环形队列的方式，提高效率
        // 生产消息,会异步处理，避免websocket的连接池的连接数用完的可能性
        pictureEditEventProducer.publishEvent(requestMessage, session, user, pictureId);
    }

    /**
     * 会话断开时的触发
     */
    @Override
    public void afterConnectionClosed(@NotNull WebSocketSession session, @NotNull CloseStatus status) throws Exception {
        Long pictureId = (Long) session.getAttributes().get("pictureId");
        UserLogin user = (UserLogin) session.getAttributes().get("user");
        // 移除当前用户的编辑状态，执行退出策略
        PictureEditMessageStrategy exitStrategy = pictureEditMessageStrategyFactory.getStrategyByMessageType(PictureEditMessageTypeEnum.EXIT_EDIT.getValue());
        exitStrategy.handle(null, session, user, pictureId);
        // 删除会话
        PictureEditBroadcast.removeSession(pictureId, session);
        // 响应
        PictureEditResponseMessage responseMessage = new PictureEditResponseMessage();
        responseMessage.setType(PictureEditMessageTypeEnum.INFO.getValue());
        String message = String.format("%s退出编辑", user.getUserName());
        responseMessage.setMessage(message);
        responseMessage.setUser(BeanUtil.toBean(user, UserVO.class));
        PictureEditBroadcast.broadcastToPicture(pictureId, responseMessage);
    }
}
